import logging

from django.db.models import Q
from drf_yasg import openapi
from drf_yasg.utils import swagger_auto_schema
from rest_framework import viewsets, status
from rest_framework.decorators import action
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from ..models import MenuModel, PermissionsModel
from ..serializers import MenuSerializer

# from ..models.menu import MenuModel

logger = logging.getLogger('erp')

"""
功能菜单的模型类
1.新增
2.查询单个功能菜单
3.查询所有功能菜单
4.查询某个父类菜单下面的所有子菜单列表
5.查询所有的顶级菜单
6.删除某一个功能菜单
7.批量删除多个菜单 传参： ids = [1,2,3]
8.修改功能菜单
"""


class MenuView(viewsets.ModelViewSet):
    queryset = MenuModel.objects.filter(delete_flag=0).all()
    serializer_class = MenuSerializer
    permission_classes = [IsAuthenticated]

    def get_queryset(self):
        logger.info(f"当前登录的用户是：{self.request.user.username}")
        """
        两种情况：
        1：查询所有菜单列表
        2：查询某个父类菜单下面的所有子菜单列表， 需要传递一个参数， 叫pid, pid==0时， 查询所有顶级菜单列表
        :return:
        """
        query_param = self.request.query_params.get("pid", None)
        if query_param:
            pid = int(query_param)
            if pid == 0:  # 查询所有顶级菜单列表
                return MenuModel.objects.filter(parent__isnull=True, delete_flag=0).all()
            else:
                return MenuModel.objects.filter(parent_id=pid, delete_flag=0).all()
        else:
            return MenuModel.objects.filter(delete_flag=0).all()

    def destroy(self, request, *args, **kwargs):
        # 修改一下删除的标记为： delete_flag = 1
        menu = self.get_object()
        menu.delete_flag = "1"
        menu.save()
        # 可能该菜单下还有很多子菜单， 这些子菜单也要修改
        MenuModel.objects.filter(parent__id=menu.id).update(delete_flag=1)
        return Response(status=status.HTTP_204_NO_CONTENT)

    del_ids = openapi.Schema(type=openapi.TYPE_OBJECT, required=['ids'], properties={
        "ids": openapi.Schema(type=openapi.TYPE_ARRAY, items=openapi.Schema(type=openapi.TYPE_INTEGER),
                              description="选择那些需要删除的ID（主键）列表")
    })

    # action装饰器可以接受2个参数
    # methods： 声明该actions对应的请求方法， 列表传递
    # detail： 声明该action的路径是否与单一资源对应， 及是否是xxx/<pk>/action方法名/
    #   True： 表示路径格式是xxx/<pk>/action方法名
    #   False： 表示路径格式是xxx/action方法名/
    @swagger_auto_schema(method="delete", request_body=del_ids, operation_description="删除")
    @action(methods=['delete'], detail=False)
    def multiple_delete(self, request, *args, **kwargs):
        delete_ids = request.data.get("ids")
        if not delete_ids:
            return Response(data={"detail": '参数错误，ids为必传参数'}, status=status.HTTP_400_BAD_REQUEST)
        elif not isinstance(delete_ids, list):
            return Response(data={"detail": '格式错误，必须为list'}, status=status.HTTP_400_BAD_REQUEST)
        # 先删除传递过来的菜单
        MenuModel.objects.filter(id__in=delete_ids).update(delete_flag=1)
        # 后删除所有的子功能菜单
        for m_id in delete_ids:
            MenuModel.objects.filter(parent__id=m_id).update(delete_flag=1)
        return Response(status=status.HTTP_204_NO_CONTENT)

    @action(detail=False, methods=["get"], url_path="get_menus_permissions")
    def get_menus_permissions(self, request, *args, **kwargs):
        # 当前登录用户， 根据权限查询拥有get的菜单功能列表（返回树型菜单）

        # 查询当前登录用户拥有的权限ID列表， 注意values_list返回列表， values返回字典
        permission_ids = request.user.roles.values_list("permissions", flat=True).distinct()

        # 查询拥有get权限的功能菜单的ID列表
        # 注意：特殊情况， 父菜单没有任何method， 如果是父菜单的权限也应该要出现
        menu_ids = PermissionsModel.objects.filter(id__in=permission_ids) \
            .filter(Q(method="GET") | Q(is_menu=True)).values_list("menu", flat=True).distinct()

        #  根据ID查询菜单, 列表里面是对象
        menu_list = MenuModel.objects.filter(id__in=menu_ids, delete_flag=0).all()
        serializer = MenuSerializer(instance=menu_list, many=True)
        # 通过serializer把对象变成字典
        # 封装成树型结构
        tree_dict = {}  # 代表一个父菜单
        tree_data = []
        for item in serializer.data:
            tree_dict[item['id']] = item
        for i in tree_dict:
            if tree_dict[i]['parent']:
                pid = tree_dict[i]['parent']
                parent = tree_dict[pid]
                parent.setdefault("children", []).append(tree_dict[i])
            else:
                tree_data.append(tree_dict[i])

        return Response(tree_data)
